{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modGalaxiePlanetes;

interface

uses Classes,
     sFonctionsChaines,
     modBaseType,
     ESBDates,
     modStreamUtils,
     modCore,
     SysUtils;


const
    MAX_TAILLE_PLANETE  = 40;
    MAX_TAILLE_JOUEUR   = 40;
    MAX_TAILLE_ALIANCE  = 20;

    CNT_GALAXIE_DB_FILE_FORMAT = 'Uni%d_Galaxie%d.ug';



type
    TLuneInfos = record
       Surface    : integer;
       Temperature: integer;
    end;




(*
CREATE TABLE galaxie (
    galaxy INTEGER,
    systeme INTEGER,
    position INTEGER,

    lune_surface INTEGER,
    lune_temperature INTEGER,
    lune_phalange_niv INTEGER,
    lune_porte_spatiale BOOLEAN,

    nom_planete VARCHAR(32),
    joueur VARCHAR(32),
    joueur_id INTEGER,         <--- champ important qui n'existait pas avant
    alliance VARCHAR(32),

    ruines_metal INTEGER,
    ruines_cristal INTEGER,

    last_update TIMESTAMP,

    flags INTEGER,

    PRIMARY KEY (galaxy, systeme, position)



    http://www.sqlite.org/cvstrac/wiki?p=DateAndTimeFunctions
    );

    *)


    TGalaxiePlanete = record
       Location: TPlanetLocation;

       // Nom de la planète
       NomPlanete     : string;

       // Nom du joueur
       Joueur  : string;

       // Alliance du joueur
       Alliance: string;


       // Information de la lune
       // la temperature pouvant etre negative, on se base sur la surface
       // pour s assurer que la lune existe
       Lune    : TLuneInfos;

       // inutile de spéficier le champs de ruine car il disparait de toute façon
       // extrait toute fois pour pouvoir effectuer des scans dans une meme session
       // a la recherche de ruines
       // OU pour pouvoir evacuer la flotte sur un champ de ruine
       // OU pour pouvoir observer quand un champ de ruine disparait
       Ruines: TOGRessourceAll;

       // Date de derniere mise a jour de cet emplacement de planete
       Date: int64;

       // Flags mode vacances, inactif 2 semaines, inactif 4 semaines, protection des noob trop faible/fort
       Flags: longword;


       // Pour la sauvegarde
       Position: integer;
       HaveToBeUpdatedFixed: boolean;
    end;


    
const
    CNT_GALAXIE_FLAGS_MODE_VACANCES               =   1;
    CNT_GALAXIE_FLAGS_INACTIF_2SEMAINES           =   2;
    CNT_GALAXIE_FLAGS_INACTIF_4SEMAINES           =   4;
    CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFAIBLE  =   8;
    CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFORT    =  16;
    CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE         =  32;
    CNT_GALAXIE_FLAGS_USER_BLOQUE                 =  64;
    CNT_GALAXIE_FLAGS_ASTEROIDES                  = 128;



    CNT_LATEST_VESTION = 1;
    


type

    PGalaxiePlanete = ^TGalaxiePlanete;

    TCollectionGalaxiePlanete = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}
       FFichier: string;

       FUnivers: integer;
       FGalaxie: integer;

       FLoadOnlyHeader : boolean;



       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TGalaxiePlanete;


    public
       property FichierSave: string read FFichier write FFichier;

       property LoadOnlyHeader: boolean read FLoadOnlyHeader write FLoadOnlyHeader;
       property Univers: integer read FUnivers write FUnivers;
       property Galaxie: integer read FGalaxie write FGalaxie;

       

       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TGalaxiePlanete): PGalaxiePlanete;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: PGalaxiePlanete);
      
       // Renvoi le pointeur de l'élément ajouté/modifié
       // Utilise Get_Index pour vérifier si l'élément doit être mis à jour
       function Add_Update(Element: TGalaxiePlanete): PGalaxiePlanete;
      
      
       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean; overload;

       // Cherche Element avec Get_Index et supprime LE
       // PREMIER pointeur trouvé, renvoi True si réussit
       function Delete(Element: TPlanetLocation): boolean; overload;

      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Index(Element: TPlanetLocation): integer;
       function Get_Pointeur(Element: TPlanetLocation): PGalaxiePlanete;
       function Get_Item(Index: integer): TGalaxiePlanete;
       property Itemx[Index: integer]: TGalaxiePlanete read GetItemx;
      

       procedure DeleteAllExceptThisSystemSolaire(Systeme: integer);

      
       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;
       
       function SaveToFile(Fichier: string): integer;
       function LoadFromFile(Fichier: string): integer;
       
       function SaveToStream(s: TStream): integer;
       function LoadFromStream(s: TStream): integer;


       procedure CopyFromList(List: TList);

    end;


    TCollectionGalaxyTriee = class(TList)
    private

    public
        procedure Import(src: TCollectionGalaxiePlanete);
        procedure ImportChampDeRuine(src: TCollectionGalaxiePlanete; DateAfter: int64);
        procedure TrieCoord;
        procedure TrieChampDeRuine;
    end;

    
    // Simple classe qui ne s'occupe que d'allouer la memoire pour l'element et
    // de le memoriser, cela sert lors du parsing de la page web, et aussi lorsque
    // l'on veut regrouper toute les planètes d'un même système solaire
    // En gros on s'en sert pour obtenir une liste de pointeur que l'on ne veut
    // pas libérer lors de la destruction de la classe
    TListGalaxiePlaneteSP = class(TList)
    private

    public
        function Ajout(Element: TGalaxiePlanete): PGalaxiePlanete;
        function GetFirstItemCoord: string;
        function ImportSystemSolaire(System: integer; List: TList): integer;
    end;


    TCollectionOfGalaxie = class(TList)
    private
        // La TList contient des pointeurs vers TCollectionGalaxiePlanete

        // Chaque base de données doit avoir au moins en commum le même univers
        FUnivers: integer;
    public

       // Permet de savoir si une galaxie existe déjà
       function GetGalaxiePointer(Galaxie: integer): TCollectionGalaxiePlanete;

       // Libère la classe lors de sa suppression de la liste
       function Delete(Index: integer): boolean; 


    end;


    function SaveFixedData(s: TStream; p: PGalaxiePlanete): integer;
    function LoadFixedData(s: TStream; p: PGalaxiePlanete; Version: integer = CNT_LATEST_VESTION): integer;

    function gpGetFlagsStrToUse(Flags: longword): string;
    function gpGetFlagsStrToUseWithParentheseIfExist(Flags: longword): string;

    // Tout les flags, astéroide inclu
    function gpGetFlagsStrToFullUsage(Flags: longword): string;

implementation

procedure TCollectionGalaxyTriee.ImportChampDeRuine(src: TCollectionGalaxiePlanete; DateAfter: int64);
var i: integer;
    pe: PGalaxiePlanete;
begin

    Capacity := src.Count;

    for i := 0 to src.Count - 1 do begin
       pe := src.Items[i];

       if (pe.Ruines.Metal > 0) or (pe.Ruines.Cristal > 0) then begin
          // il y a un champ de ruine
          // vérifie maintenant la durée

          if pe.Date >= DateAfter then begin
             Add(src.Items[i]);
          end;

       end;
    end;

    TrieChampDeRuine;
end;

procedure TCollectionGalaxyTriee.Import(src: TCollectionGalaxiePlanete);
var i: integer;
begin

    Capacity := src.Count;

    for i := 0 to src.Count - 1 do begin
       Add(src.Items[i]);
    end;

    TrieCoord;
end;

function brCompareElements(Item1, Item2: Pointer): Integer;
var e1, e2: PGalaxiePlanete;
begin

    // Compare renvoie < 0 si Item1 est inférieur à Item2,
    //                   0 s'ils sont égaux
    //                 > 0 si Item1 est supérieur à Item2
    // Voir http://alphomega.developpez.com/TriTList/
    // pour savoir comment trier sur plusieurs critére


    e1 := Item1;
    e2 := Item2;

    Result := trieCompareLocation(e1.Location, e2.Location);

end;

function brCompareElementsChampDeRuine(Item1, Item2: Pointer): Integer;
var e1, e2: PGalaxiePlanete;
    cdr1, cdr2: integer;
begin

    // Compare renvoie < 0 si Item1 est inférieur à Item2,
    //                   0 s'ils sont égaux
    //                 > 0 si Item1 est supérieur à Item2
    // Voir http://alphomega.developpez.com/TriTList/
    // pour savoir comment trier sur plusieurs critére

    e1 := Item1;
    e2 := Item2;

    cdr1 := e1.Ruines.Metal + e1.Ruines.Cristal;
    cdr2 := e2.Ruines.Metal + e2.Ruines.Cristal;

    // on trie dans l'ordre décroissant
    if cdr1 > cdr2 then begin
       Result := -1;
    end else if cdr1 = cdr2 then begin
       Result := 0;
    end else begin
       Result := 1;
    end;

end;


procedure TCollectionGalaxyTriee.TrieChampDeRuine;
begin
    Sort(brCompareElementsChampDeRuine);
end;

procedure TCollectionGalaxyTriee.TrieCoord;
begin
    Sort(brCompareElements);
end;

function gpGetFlagsStrToFullUsage(Flags: longword): string;
begin

   Result := gpGetFlagsStrToUse(Flags);

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE, Flags) then
      Result := Result + 'F';

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_ASTEROIDES, Flags) then
      Result := Result + 'A';

end;

function gpGetFlagsStrToUse(Flags: longword): string;
begin

   Result := '';

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_MODE_VACANCES, Flags) then
      Result := Result + 'v';

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_INACTIF_2SEMAINES, Flags) then
      Result := Result + 'i';
   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_INACTIF_4SEMAINES, Flags) then
      Result := Result + 'I';

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFAIBLE, Flags) then
      Result := Result + '-';
   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFORT, Flags) then
      Result := Result + '+';

   if sfcFlagsIsIn(CNT_GALAXIE_FLAGS_USER_BLOQUE, Flags) then
      Result := Result + 'g';




end;

function gpGetFlagsStrToUseWithParentheseIfExist(Flags: longword): string;
begin
   Result := gpGetFlagsStrToUse(Flags);

   if Result <> '' then
      Result := ' (' + Result + ')';

end;


function TListGalaxiePlaneteSP.ImportSystemSolaire(System: integer; List: TList): integer;
var i: integer;
    pe: PGalaxiePlanete;
begin

    Result := 0;
    if List.Count = 0 then exit;

    for i := 0 to List.Count - 1 do begin
        pe := List.Items[i];

        if pe.Location.SystemSolaire = System then begin
           Add(pe);
           Inc(Result);
        end;

    end;


end;



////////////////////////////////////////////////////////////////////////////////
//

function TCollectionOfGalaxie.GetGalaxiePointer(Galaxie: integer): TCollectionGalaxiePlanete;
var i: integer;
begin

    if (Count <= 0) then begin
       Result := nil;
       exit;
    end;

    for i := 0 to Count - 1 do begin
        Result := Items[i];

        if Result.Galaxie = Galaxie then
           exit;

    end;

    Result := nil;

end;



function TCollectionOfGalaxie.Delete(Index: integer): boolean;
var pe: TCollectionGalaxiePlanete;
begin

    if (Index < 0) or (Index >= Count) then begin
       Result := false;
       exit;
    end;

    pe := Items[Index];
    pe.Free;

    inherited Delete(Index);

end;



procedure TCollectionGalaxiePlanete.CopyFromList(List: TList);
var i, jOld: integer;
    pe, peOld: PGalaxiePlanete;
begin

    if List.Count = 0 then exit;


    for i := 0 to List.Count - 1 do begin

        // Vérifie si l'élément n'existe pas déjà
        pe := List.Items[i];
        pe.HaveToBeUpdatedFixed := true;


        jOld := Get_Index(pe.Location);

        if jOld >= 0 then begin
           peOld := Items[jOld];

           // sauvegarde la position dans le nouvel élément
           pe.Position             := peOld.Position;


           // libère l'ancien élément
           Dispose(peOld);

           // et le remplace par le nouveau
           Items[jOld] := pe;

        end else begin
           // simple ajout
           pe.Position := -1;

           SimpleAdd(pe);

        end;

    end;


end;


function TCollectionGalaxiePlanete.LoadFromStream(s: TStream): integer;
var Element: PGalaxiePlanete;
    i :integer;
    cCount: integer;
    dbVersion : integer;
begin

    // se place au debut du fichier
    s.Seek(0, soBeginning);


    // Charge le numero de version avant tout
    if s.Read(dbVersion, SizeOf(dbVersion)) < SizeOf(dbVersion) then begin
       Result := -1;
       exit;
    end;


    // Charge l univers et la galaxie
    if s.Read(FUnivers, SizeOf(FUnivers)) < SizeOf(FUnivers) then begin
       Result := -1;
       exit;
    end;

    if s.Read(FGalaxie, SizeOf(FGalaxie)) < SizeOf(FGalaxie) then begin
       Result := -1;
       exit;
    end;



    // On ne charge pas les rapports brut zippé
    if s.Read(cCount, SizeOf(cCount)) < SizeOf(cCount) then begin
       Result := -1;
       exit;
    end;


    if FLoadOnlyHeader then begin
       Result := 1;
       exit;
    end;

    Element := nil;


    for i := 1 to cCount do begin
       if Element = nil then
          New(Element);


       Element.Position := s.Position;

       if LoadFixedData(s, Element, dbVersion) > 0 then begin
          Element.HaveToBeUpdatedFixed := false;
          SimpleAdd(Element);
          Element := nil;

       end else
          // fin du fichier alors
          break;

    end;

    if Element <> nil then
       Dispose(Element);

    Result := cCount;


end;

function TCollectionGalaxiePlanete.SaveToStream(s: TStream): integer;
var pe: PGalaxiePlanete;
    i :integer;
    cCount: integer;
    dbVersion: integer;
begin

    if Count = 0 then exit;



    // se place au debut du fichier
    s.Seek(0, soBeginning);


    // Ecrit le numero de version avant tout
    dbVersion := CNT_LATEST_VESTION;
    s.Write(dbVersion, SizeOf(dbVersion));


    // Ecrit l univers et la galaxie
    s.Write(FUnivers, SizeOf(FUnivers));

    s.Write(FGalaxie, SizeOf(FGalaxie));


    // Puis ecrit le nombre d'élément
    cCount := Count;
    s.Write(cCount, SizeOf(cCount));



    Result := 0;

    for i := 0 to Count - 1 do begin
        pe := Items[i];



        if pe.Position < 0 then begin
           // L'élément a été ajouté en cours de cette session
           // Ajoute à la fin du stream
           s.Seek(0, soEnd);

           pe.Position             := s.Position;
           pe.HaveToBeUpdatedFixed := false;

           SaveFixedData(s, pe);
           Inc(Result);

        end else begin
           // Position >= 0

           if pe.HaveToBeUpdatedFixed then begin
              s.Seek(pe.Position, soBeginning);

              SaveFixedData(s, pe);
              Inc(Result);

              pe.HaveToBeUpdatedFixed := false;
           end;

        end;

    end;


    // Result correspond au nombre d'élément qui ont été sauvegardé


end;

function LoadFixedData(s: TStream; p: PGalaxiePlanete; Version: integer = CNT_LATEST_VESTION): integer;
var r: integer;
    i: integer;
begin

    Result := -1;

    with p^ do begin
       r := s.Read(Location, SizeOf(Location));
       if r < SizeOf(Location) then exit;

       r := s.Read(Lune, SizeOf(Lune));
       if r < SizeOf(Lune) then exit;

       r := s.Read(Ruines, SizeOf(Ruines));
       if r < SizeOf(Ruines) then exit;

       r := s.Read(Date, SizeOf(Date));
       if r < SizeOf(Date) then exit;

       r := s.Read(Flags, SizeOf(Flags));
       if r < SizeOf(Flags) then exit;

       NomPlanete := msuStringLoadFromStreamFixedSize(s, r, MAX_TAILLE_PLANETE);
       if r <= 0 then exit;

       Joueur     := msuStringLoadFromStreamFixedSize(s, r, MAX_TAILLE_JOUEUR);
       if r <= 0 then exit;

       Alliance   := msuStringLoadFromStreamFixedSize(s, r, MAX_TAILLE_ALIANCE);
       if r <= 0 then exit;

    end;

    Result := 1;


end;


function SaveFixedData(s: TStream; p: PGalaxiePlanete): integer;
var r: integer;
begin
    Result := -1;

    with p^ do begin
       r := s.Write(Location, SizeOf(Location));
       if r < SizeOf(Location) then exit;

       r := s.Write(Lune, SizeOf(Lune));
       if r < SizeOf(Lune) then exit;

       r := s.Write(Ruines, SizeOf(Ruines));
       if r < SizeOf(Ruines) then exit;

       r := s.Write(Date, SizeOf(Date));
       if r < SizeOf(Date) then exit;

       r := s.Write(Flags, SizeOf(Flags));
       if r < SizeOf(Flags) then exit;


       msuStringSaveToStreamFixedSize(NomPlanete, s, MAX_TAILLE_PLANETE);
       msuStringSaveToStreamFixedSize(Joueur    , s, MAX_TAILLE_JOUEUR);
       msuStringSaveToStreamFixedSize(Alliance  , s, MAX_TAILLE_ALIANCE);

    end;

    Result := 1;

end;


{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionGalaxiePlanete                                     **
 *******************************************************************************
 *******************************************************************************}
 

(*
// Lorsque l'on sauvegarde un token du genre t1;t2;t3
// Cette fonction renvoi le token suivant 
// Attention: si deux délimiteurs se suivent, une chaine vide sera renvoyée)
function TCollectionGalaxiePlanete.LoadFromFileGetNextValeur(var ChaineLu: string): string;
var xPos: integer;
begin
     Result := '';

     xPos := pos(',', ChaineLu);

     if xPos = 0 then begin
        Result := ChaineLu;
        ChaineLu := '';
        exit;
     end;

     Result := copy(ChaineLu, 1, xPos - 1);
     System.Delete(ChaineLu, 1, xPos);
end;
*)

function TCollectionGalaxiePlanete.LoadFromFile(Fichier: string): integer;
var F: TFileStream;
begin

    if Fichier = '' then Fichier := FFichier;

    // ATTENTION: Les éléments sont effacés avant le chargement, à modifier en fonction de ce que l'on veut
    Clear;

    FUnivers := -1;
    FGalaxie := -1;


    Result  := -1;
    Fichier := sfcUnixPathToDosPath(Fichier);
    FFichier := Fichier;
    if FileExists(Fichier) = false then exit;

    try
       F := TFileStream.Create(Fichier, fmOpenRead);
    except
       F.Free;
       F := nil;
    end;

    // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
    if F = nil then begin
       exit;
    end;

    Result := LoadFromStream(F);


    // Fermeture du fichier
    F.Free;
end;


function TCollectionGalaxiePlanete.SaveToFile(Fichier: string): integer;
var F: TFileStream;
begin

    Result := -2;


    if Fichier = '' then Fichier := FFichier;

    if (Fichier = '') then begin
       Result := -18;
       exit;
    end;

    try
      if FileExists(Fichier) then
         F := TFileStream.Create(Fichier, fmOpenWrite)
      else
         F := TFileStream.Create(Fichier, fmCreate);

    except
      F.Free;
      F := nil;
    end;



    if F <> nil then begin
       // Résultat
       Result := SaveToStream(F);

       // Ferme le fichier
       F.Free;

    end else begin
       Result := -3;
    end;
end;

constructor TCollectionGalaxiePlanete.Create;
begin
    
    // Héritage
    InHerited Create;
    
    
    
    // Code pour l'initialisation ici
    FUnivers := -1;
    FGalaxie := -1;

    FLoadOnlyHeader := false;
end;

destructor TCollectionGalaxiePlanete.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;


procedure TCollectionGalaxiePlanete.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;


function TCollectionGalaxiePlanete.Get_Pointeur(Element: TPlanetLocation): PGalaxiePlanete;
var i: integer;
begin
   Result := nil;
   
   i := Get_Index(Element);
   if i < 0 then exit;
   Result := Items[i];
end;

procedure TCollectionGalaxiePlanete.DeleteAllExceptThisSystemSolaire(Systeme: integer);
var i: integer;
    pElement: PGalaxiePlanete;
begin

   if Count <= 0 then exit;

   for i := Count - 1 downto 0 do begin
      pElement := Items[i];

      if pElement.Location.SystemSolaire <> Systeme then begin
         Delete(i);
      end;

   end;

end;

function TCollectionGalaxiePlanete.Get_Index(Element: TPlanetLocation): integer;
var i: integer;
    pElement: PGalaxiePlanete;
    iComp: TPlanetLocation;
begin

   Result := -1;

   if Count <= 0 then exit;

   iComp := Element;

   if Element.Position > CNT_POSITION_LUNE then begin
      // c'est une lune
      iComp.Position := iComp.Position - CNT_POSITION_LUNE;
   end;

   for i := 0 to Count - 1 do begin
      pElement := Items[i];

      if CompareLocation(pElement.Location, iComp) then begin
         Result := i;
         exit;
      end;
   end;

end;

function TCollectionGalaxiePlanete.Add_Update(Element: TGalaxiePlanete): PGalaxiePlanete;
var i : integer;
begin
     
     Result := nil;
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     i := Get_Index(Element.Location);        {### Neccessite adpation en fonction du type record  ### }
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     if i < 0 then begin 
        // L'élément n'existe pas, l'ajoute
        Result  := Add(Element);
     end else begin
        // L'élément existe déjà, le met à jour
        Result  := Items[i];     // Obtient le pointeur
        Result^ := Element;
     end;
     
end;




function TCollectionGalaxiePlanete.Get_Item(Index: integer): TGalaxiePlanete;
var pElement: PGalaxiePlanete;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionGalaxiePlanete.Delete(Index: integer): boolean;
var pElement: PGalaxiePlanete;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;

function TCollectionGalaxiePlanete.Delete(Element: TPlanetLocation): boolean;
var i : integer;
begin

    Result := false;
    i      := Get_Index(Element);

    if i >= 0 then begin
       // Element trouvé
       // Le supprime
       Delete(i);

       // Même si la suppression Echoue on renvoi True
       // Car l'élément a été trouvé
       Result := true;
    end;
end;


function TCollectionGalaxiePlanete.Add(Element: TGalaxiePlanete): PGalaxiePlanete;
var pElement: PGalaxiePlanete;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Recopie les données dans l'emplacement pointé
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionGalaxiePlanete.SimpleAdd(Pointeur: PGalaxiePlanete);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionGalaxiePlanete.GetItemx(Index: integer): TGalaxiePlanete;
var pElement: PGalaxiePlanete;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;




////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Simple list ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


function TListGalaxiePlaneteSP.Ajout(Element: TGalaxiePlanete): PGalaxiePlanete;
var pElement: PGalaxiePlanete;
begin

    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Recopie les données dans l'élément pointé

    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;

end;

function TListGalaxiePlaneteSP.GetFirstItemCoord: string;
var pElement: PGalaxiePlanete;
begin
    if Count = 0 then begin
       Result := '(aucune)';
       exit;
    end;

    pElement := Items[0];

    Result := mbtPlanetLocationToStr(pElement.Location) + ' - ' + pElement.NomPlanete;



end;





end.
